www.gusucode.com > VC++ 自制SQL数据库,含有服务端+客户端-源码程序 > VC++ 自制SQL数据库,含有服务端+客户端-源码程序/code/Server/Cache.cpp
// cache.cpp // Download by http://www.NewXing.com #include "stdafx.h" #include "miniSQL.h" #include "Cache.h" extern CMiniSQLApp theApp; //////////////////////////////////////////////////////////////////// // CBLOCK CBlock::CBlock() { Clear(); } CBlock::~CBlock() { } void CBlock::Clear() { status.dirty = status.lock = false; status.level = 0; status.pos = 0; status.pFile = NULL; } Status* CBlock::GetStatus() { return &status; } char* CBlock::GetBlock() { status.level++; return Block; } UINT CBlock::Read(CFile *pFile, long pos) { if( !pFile ) throw Error( FILE_OPEN_ERROR, 0, pFile->GetFileName() ); // status.dirty = status.lock = false; //just no change status.level = 1; status.pos = pos; status.pFile = pFile; long lPos = status.pos << BLOCK_OFFSET; status.pFile->Seek(lPos, CFile::begin); return status.pFile->Read(Block, sizeof(Block)); } bool CBlock::Write() { if( status.pFile && status.dirty ){ long lPos = status.pos << BLOCK_OFFSET; status.pFile->Seek(lPos, CFile::begin); status.pFile->Write(Block, sizeof(Block)); } return true; } ///////////////////////////////////////////////////////////////////// // CCACHE int CCache::Next() { //Find the next Block which can be used //using Clockwise algorithm int i = (last + 1) % CACHE_SIZE; Status* status = Cache[i].GetStatus(); while( status->level ){ if( !status->lock ) status->level--; i = (i + 1) % CACHE_SIZE; status = Cache[i].GetStatus(); } return i; } int CCache::Find(POSITION fPos, long pos) { //Find the specified Block Status *status; for(int i = CACHE_SIZE - 1; i >= 0; i--){ status = Cache[i].GetStatus(); if( status->pFile == FileList.GetAt(fPos) && status->pos == pos ) return i; } return -1; } POSITION CCache::Find(CFile* pFile) { //Find the position in the list corresponding to pFile POSITION pos = FileList.GetHeadPosition(); while( pos ){ POSITION old = pos; if( FileList.GetNext(pos) == pFile ) return old; } return NULL; } POSITION CCache::Open( const char* fname, const char* fsuf ) { //open a file; char file_name[ FILE_NAME_LEN + 1 ]; ::strncpy( file_name, fname, MAIN_NAME_LEN ); file_name[ MAIN_NAME_LEN ] = 0; ::strncat( file_name, fsuf, FILE_NAME_LEN - MAIN_NAME_LEN ); file_name[ FILE_NAME_LEN ] = 0; POSITION pos = FileList.GetHeadPosition(); while( pos ){ POSITION old = pos; if( FileList.GetNext(pos)->GetFileName() == file_name ) return old; } //check if the file exists CFileStatus status; CFile* pFile; CString path = theApp.dir; path = path + "\\" + file_name; if( !CFile::GetStatus( path, status ) ) { if( !( pFile = new CFile( path, CFile::modeCreate | CFile::modeReadWrite) ) ) throw Error( FILE_CREATE_ERROR, 0, path ); } else { if( !( pFile = new CFile( path, CFile::modeReadWrite ) ) ) throw Error( FILE_OPEN_ERROR, 0, path ); } //add to list FileList.AddTail(pFile); return FileList.GetTailPosition(); } void CCache::Close(POSITION fPos, bool reserve) { //check if fPos exist bool flag = false; for(int i = 0; i < FileList.GetCount(); i++) if( FileList.FindIndex( i ) == fPos ){ flag = true; break ; } if( !flag )return ; //close the cache specified by fPos CFile* pFile = FileList.GetAt ( fPos ); if( pFile == NULL ) return ; for(i = 0; i < CACHE_SIZE; i++) if( Cache[i].status.pFile == pFile ){ if( reserve )Cache[i].Write(); Cache[i].Clear(); } CString fPath = pFile->GetFilePath(); pFile->Close(); if( !reserve ){ TRY{ CFile::Remove( fPath ); } CATCH( CFileException, e ){ #ifdef _DEBUG Message( "File \' " + fPath + " \' can't be removed.\n" ); #endif } END_CATCH } FileList.RemoveAt( fPos ); pFile = NULL; } void CCache::Clear() { //clear the cache for( int i = 0; i < CACHE_SIZE; i++ ){ Cache[i].Write(); Cache[i].Clear(); } POSITION pos = FileList.GetHeadPosition(); while( pos ) FileList.GetNext( pos )->Close(); FileList.RemoveAll(); last = -1; } CBlock* CCache::FetchBlock(POSITION fPos, long pos) { //check if fPos exist bool flag = false; for(int i = 0; i < FileList.GetCount(); i++) if( FileList.FindIndex( i ) == fPos ){ flag = true; break ; } if( !flag )return NULL; //fetch a specified data into memory if( ( i = Find( fPos, pos ) ) == -1 ){ i = Next(); Cache[i].Write(); Cache[i].Read( FileList.GetAt( fPos ), pos ); } last = i; return &Cache[i]; } void CCache::Read( POSITION fPos, long address, void* vdes, UINT sz) { //read data from hareware to memory char* des = ( char* ) vdes; UINT m_sz; CBlock* pBlock; while( sz > 0 ){ m_sz = BLOCK_SIZE - address % BLOCK_SIZE; if( m_sz > sz ) m_sz = sz; pBlock = FetchBlock( fPos, address >> BLOCK_OFFSET ); ::memcpy( des, pBlock->GetBlock() + address % BLOCK_SIZE, m_sz ); des += m_sz; address += m_sz; sz -= m_sz; } } void CCache::Write( POSITION fPos, long address, const void* vsrc, UINT sz) { //write data in memory, change the cache const char* src = ( const char* ) vsrc; UINT m_sz; CBlock* pBlock; while( sz > 0 ){ m_sz = BLOCK_SIZE - address % BLOCK_SIZE; if( m_sz > sz ) m_sz = sz; pBlock = FetchBlock( fPos, address >> BLOCK_OFFSET ); ::memcpy( pBlock->GetBlock() + address % BLOCK_SIZE, src, m_sz ); pBlock->status.dirty = true; src += m_sz; address += m_sz; sz -= m_sz; } } ///////////////////////////////////////////////////////////////////// // THE EXTERNAL OBJECT, ONE AND THE ONLY CCache cache; ///////////////////////////////////////////////////////////////////// // CFILEAPI CFileAPI::CFileAPI( const char* fname, const char* fsuf ) { //construction //for read CFileStatus status; CString path = theApp.dir; path = path + "\\" + fname + fsuf; if( !CFile::GetStatus( path, status ) ) throw Error( FILE_OPEN_ERROR, 0, path ); fPos = cache.Open( fname, fsuf ); LoadHead(); } CFileAPI::CFileAPI( const char* fname, const char* fsuf, long rec_len, long attr_len, bool del_sign ) { //construction //open a new file and write RecCount = AllocList = 0; RecLen = rec_len; AttrBlocks = ( attr_len + BLOCK_SIZE - 1 ) / BLOCK_SIZE; DelSign = del_sign; fPos = cache.Open( fname, fsuf ); SaveHead(); } CFileAPI::~CFileAPI() { //destruction if( fPos ) cache.Close( fPos ); } void CFileAPI::LoadHead() { //load all the variables cache.Read( fPos, 0, &AllocList, ( char* ) &fPos - ( char* ) &AllocList ); } void CFileAPI::SaveHead() { //save the variables cache.Write( fPos, 0, &AllocList, ( char* ) &fPos - ( char* ) &AllocList ); } //IMPLEMENTATIONS long CFileAPI::ntop( long n ) { //change the number of records to file position or address return ( DelSign ? ( sizeof( bool ) + RecLen ) * n + sizeof( bool ) : RecLen * n ) + BLOCK_SIZE * ( AttrBlocks + 1 ); } void CFileAPI::ReadAttr( void* des, UINT len ) { cache.Read( fPos, BLOCK_SIZE, des, len ); } void CFileAPI::WriteAttr( const void* src, UINT len ) { cache.Write( fPos, BLOCK_SIZE, src, len ); } void CFileAPI::ReadRec( long n, void* des ) { cache.Read( fPos, ntop( n ), des, RecLen ); } void CFileAPI::WriteRec( long n, const void* src ) { cache.Write( fPos, ntop( n ), src, RecLen ); } CBlock* CFileAPI::FetchBlock( long bpos ) { return cache.FetchBlock( fPos, ++bpos + AttrBlocks ); } long CFileAPI::AllocRec() { //allocate a new record long NewAlloc = AllocList; if( AllocList == RecCount ) AllocList = ++RecCount ; else{ cache.Read( fPos, ntop( NewAlloc ), &AllocList, sizeof( long ) ); if( DelSign ){ bool sign = false; cache.Write( fPos, ntop( NewAlloc ) - sizeof( bool ), &sign, sizeof( bool ) ); } } SaveHead(); return NewAlloc; } void CFileAPI::RemoveRec( long n ) { //remove a record if( DelSign ) { bool sign = true; cache.Write( fPos, ntop( n ) - sizeof( bool ), &sign, sizeof( bool ) ); } cache.Write( fPos, ntop( n ), &AllocList, sizeof( long ) ); AllocList = n; SaveHead(); } long CFileAPI::NextRec( long n ) { //find the next non-empty record if( n >= RecCount - 1 ) return -1; if( !DelSign ) return ++n; bool sign; do cache.Read( fPos, ntop( ++n ) - sizeof( bool ), &sign, sizeof( bool ) ); while( sign && n < RecCount - 1 ); return sign ? -1 : n; } long CFileAPI::FirstRec() { //return the first non-empty record return NextRec( -1 ); } void CFileAPI::Close() { cache.Close( fPos ); fPos = NULL; } void CFileAPI::Drop() { //drop the file API for certain reasons cache.Close( fPos, false ); fPos = NULL; }